﻿// -------------------------------------------------------------------------
//    @FileName         :    BagPageOpMgrTest.cpp
//    @Author           :    gaoyi
//    @Date             :    2025/1/20
//    @Email            :    445267987@qq.com
//    @Module           :    BagPageOpMgrTest
//
// -------------------------------------------------------------------------

#include "BagSystemTestBase.h"
#include "MockItemDesc.h"

/**
 * @brief 背包操作管理器测试类
 * 
 * 测试背包操作管理器的核心功能：
 * - 事务性操作管理
 * - 批量物品添加和删除
 * - 操作提交和回滚
 * - 多背包页面协调
 * - 物品移动和交换
 */
class BagPageOpMgrTest : public BagSystemTestBase {
protected:
    void SetUp() override {
        BagSystemTestBase::SetUp();
        
        // 创建测试玩家
        m_testPlayer = CreateTestPlayer();
        
        // 创建背包操作管理器
        m_bagOpMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
        m_bagOpMgrNoCommit = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, false);
    }
    
    void TearDown() override {
        m_bagOpMgr = nullptr;
        m_bagOpMgrNoCommit = nullptr;
        m_testPlayer = nullptr;
        
        BagSystemTestBase::TearDown();
    }

protected:
    NFPlayer* m_testPlayer;
    NFBagPageOpMgr* m_bagOpMgr;
    NFBagPageOpMgr* m_bagOpMgrNoCommit;
};

// === 基础功能测试 ===

/**
 * @brief 测试背包操作管理器初始化
 */
TEST_F(BagPageOpMgrTest, InitializationTest) {
    ASSERT_NE(m_bagOpMgr, nullptr) << "背包操作管理器创建失败";
    ASSERT_NE(m_bagOpMgrNoCommit, nullptr) << "无提交背包操作管理器创建失败";
    
    // 验证操作原因
    ASSERT_EQ(m_bagOpMgr->GetPackageOpReason(), TEST_REASON_SYSTEM) << "操作原因不正确";
    ASSERT_EQ(m_bagOpMgrNoCommit->GetPackageOpReason(), TEST_REASON_SYSTEM) << "无提交操作原因不正确";
}

/**
 * @brief 测试添加单个物品
 */
TEST_F(BagPageOpMgrTest, AddSingleItemTest) {
    // 测试添加普通物品
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    int addedCount = 0;
    int result = m_bagOpMgr->AddToBag(willAdd, 1, &addedCount);
    ASSERT_EQ(result, 0) << "添加物品失败";
    ASSERT_EQ(addedCount, 1) << "添加数量不正确";
    
    // 提交操作
    int commitResult = m_bagOpMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交操作失败";
    
    // 验证物品确实添加到背包
    int totalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, totalCount);
    ASSERT_EQ(totalCount, 1) << "背包中物品数量不正确";
}

/**
 * @brief 测试批量添加物品
 */
TEST_F(BagPageOpMgrTest, AddMultipleItemsTest) {
    // 准备多个物品
    std::vector<WillAddItemData> willAddItems;
    std::vector<int> wantAddNums;
    
    for (int i = 0; i < 5; ++i) {
        WillAddItemData item;
        item.itemId = TestItemIds::NORMAL_ITEM_1 + i;
        item.count = 1;
        item.quality = TestQuality::WHITE;
        item.bind = false;
        willAddItems.push_back(item);
        wantAddNums.push_back(1);
    }
    
    // 批量添加
    std::vector<int> addedNums;
    int result = m_bagOpMgr->AddToBag(willAddItems, wantAddNums, &addedNums);
    ASSERT_EQ(result, 0) << "批量添加物品失败";
    
    // 验证添加数量
    ASSERT_EQ(addedNums.size(), willAddItems.size()) << "返回的添加数量数组大小不正确";
    for (size_t i = 0; i < addedNums.size(); ++i) {
        ASSERT_EQ(addedNums[i], 1) << "第" << i << "个物品添加数量不正确";
    }
    
    // 提交操作
    int commitResult = m_bagOpMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交操作失败";
    
    // 验证所有物品都添加到背包
    for (const auto& item : willAddItems) {
        int totalCount = 0;
        NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, item.itemId, totalCount);
        ASSERT_EQ(totalCount, 1) << "物品" << item.itemId << "数量不正确";
    }
}

/**
 * @brief 测试堆叠物品添加
 */
TEST_F(BagPageOpMgrTest, AddStackableItemsTest) {
    // 添加可堆叠物品
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::STACKABLE_ARROW;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    // 第一次添加100个
    int addedCount1 = 0;
    int result1 = m_bagOpMgr->AddToBag(willAdd, 100, &addedCount1);
    ASSERT_EQ(result1, 0) << "第一次添加堆叠物品失败";
    ASSERT_EQ(addedCount1, 100) << "第一次添加数量不正确";
    
    // 第二次添加50个
    int addedCount2 = 0;
    int result2 = m_bagOpMgr->AddToBag(willAdd, 50, &addedCount2);
    ASSERT_EQ(result2, 0) << "第二次添加堆叠物品失败";
    ASSERT_EQ(addedCount2, 50) << "第二次添加数量不正确";
    
    // 提交操作
    int commitResult = m_bagOpMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交操作失败";
    
    // 验证总数量
    int totalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::STACKABLE_ARROW, totalCount);
    ASSERT_EQ(totalCount, 150) << "堆叠物品总数量不正确";
}

/**
 * @brief 测试物品删除
 */
TEST_F(BagPageOpMgrTest, DeleteItemsTest) {
    // 先添加一些物品
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::STACKABLE_ARROW;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    int addedCount = 0;
    m_bagOpMgr->AddToBag(willAdd, 200, &addedCount);
    m_bagOpMgr->Commit();
    
    // 创建新的操作管理器进行删除
    NFBagPageOpMgr* delMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 删除部分物品
    int deletedCount = 0;
    int deleteResult = delMgr->DelItems(TestItemIds::STACKABLE_ARROW, 80, &deletedCount);
    ASSERT_EQ(deleteResult, 0) << "删除物品失败";
    ASSERT_EQ(deletedCount, 80) << "删除数量不正确";
    
    // 提交删除操作
    int commitResult = delMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交删除操作失败";
    
    // 验证剩余数量
    int totalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::STACKABLE_ARROW, totalCount);
    ASSERT_EQ(totalCount, 120) << "删除后剩余数量不正确";
}

/**
 * @brief 测试物品交换
 */
TEST_F(BagPageOpMgrTest, SwapItemsTest) {
    // 添加两个不同的物品
    WillAddItemData item1, item2;
    item1.itemId = TestItemIds::WEAPON_SWORD;
    item1.count = 1;
    item1.quality = TestQuality::WHITE;
    item1.bind = false;
    
    item2.itemId = TestItemIds::ARMOR_HELMET;
    item2.count = 1;
    item2.quality = TestQuality::WHITE;
    item2.bind = false;
    
    m_bagOpMgr->AddToBag(item1, 1, nullptr);
    m_bagOpMgr->AddToBag(item2, 1, nullptr);
    m_bagOpMgr->Commit();
    
    // 创建新的操作管理器进行交换
    NFBagPageOpMgr* swapMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 交换物品位置
    int swapResult = swapMgr->SwapGrid(TEST_BAG_TYPE_NORMAL, 0, TEST_BAG_TYPE_NORMAL, 1);
    ASSERT_EQ(swapResult, 0) << "交换物品失败";
    
    // 提交交换操作
    int commitResult = swapMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交交换操作失败";
    
    // 验证交换结果
    NFBagPage* bagPage = NFServicePackage::GetBagPage(m_testPlayer, TEST_BAG_TYPE_NORMAL);
    ASSERT_NE(bagPage, nullptr) << "获取背包页面失败";
    
    const NFGridItem* itemAt0 = bagPage->GetItem(0);
    const NFGridItem* itemAt1 = bagPage->GetItem(1);
    
    ASSERT_NE(itemAt0, nullptr) << "位置0的物品不存在";
    ASSERT_NE(itemAt1, nullptr) << "位置1的物品不存在";
    
    // 验证物品已交换
    ASSERT_EQ(itemAt0->GetItemID(), TestItemIds::ARMOR_HELMET) << "位置0的物品ID不正确";
    ASSERT_EQ(itemAt1->GetItemID(), TestItemIds::WEAPON_SWORD) << "位置1的物品ID不正确";
}

/**
 * @brief 测试事务回滚
 */
TEST_F(BagPageOpMgrTest, TransactionRollbackTest) {
    // 获取初始物品数量
    int initialCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, initialCount);
    
    // 使用无提交的操作管理器
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    int addedCount = 0;
    int result = m_bagOpMgrNoCommit->AddToBag(willAdd, 5, &addedCount);
    ASSERT_EQ(result, 0) << "添加物品失败";
    ASSERT_EQ(addedCount, 5) << "添加数量不正确";
    
    // 不提交操作，直接销毁操作管理器（模拟回滚）
    m_bagOpMgrNoCommit = nullptr;
    
    // 验证物品数量没有改变
    int finalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, finalCount);
    ASSERT_EQ(finalCount, initialCount) << "回滚后物品数量应该不变";
}

/**
 * @brief 测试尽可能添加物品
 */
TEST_F(BagPageOpMgrTest, AddAsPossibleTest) {
    // 创建一个小容量的背包环境
    // 这里假设背包容量有限制，我们尝试添加超出容量的物品
    
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    // 尝试添加大量物品（超出背包容量）
    int addedCount = 0;
    int result = m_bagOpMgr->AddToBag(willAdd, 1000, true, &addedCount);
    
    // 应该能添加一些物品，但不是全部
    ASSERT_EQ(result, 0) << "尽可能添加物品失败";
    ASSERT_GT(addedCount, 0) << "应该至少添加一些物品";
    ASSERT_LT(addedCount, 1000) << "不应该添加全部物品";
    
    // 提交操作
    int commitResult = m_bagOpMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交操作失败";
    
    // 验证实际添加的数量
    int totalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, totalCount);
    ASSERT_EQ(totalCount, addedCount) << "实际添加数量与预期不符";
}

/**
 * @brief 测试物品足够性检查
 */
TEST_F(BagPageOpMgrTest, ItemSufficientCheckTest) {
    // 先添加一些物品
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::STACKABLE_ARROW;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    m_bagOpMgr->AddToBag(willAdd, 100, nullptr);
    m_bagOpMgr->Commit();
    
    // 创建新的操作管理器检查物品足够性
    NFBagPageOpMgr* checkMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 检查足够的物品
    bool enough1 = false;
    int checkResult1 = checkMgr->HaveEnoughItem(TestItemIds::STACKABLE_ARROW, 50, enough1);
    ASSERT_EQ(checkResult1, 0) << "检查物品足够性失败";
    ASSERT_TRUE(enough1) << "应该有足够的物品";
    
    // 检查不足够的物品
    bool enough2 = false;
    int checkResult2 = checkMgr->HaveEnoughItem(TestItemIds::STACKABLE_ARROW, 200, enough2);
    ASSERT_EQ(checkResult2, 0) << "检查物品足够性失败";
    ASSERT_FALSE(enough2) << "不应该有足够的物品";
    
    // 检查不存在的物品
    bool enough3 = false;
    int checkResult3 = checkMgr->HaveEnoughItem(TestItemIds::WEAPON_SWORD, 1, enough3);
    ASSERT_EQ(checkResult3, 0) << "检查物品足够性失败";
    ASSERT_FALSE(enough3) << "不存在的物品应该不足够";
}

/**
 * @brief 测试获取物品数量
 */
TEST_F(BagPageOpMgrTest, GetItemCountTest) {
    // 添加不同数量的物品
    WillAddItemData willAdd1, willAdd2;
    willAdd1.itemId = TestItemIds::STACKABLE_ARROW;
    willAdd1.count = 1;
    willAdd1.quality = TestQuality::WHITE;
    willAdd1.bind = false;
    
    willAdd2.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd2.count = 1;
    willAdd2.quality = TestQuality::WHITE;
    willAdd2.bind = false;
    
    m_bagOpMgr->AddToBag(willAdd1, 150, nullptr);
    m_bagOpMgr->AddToBag(willAdd2, 3, nullptr);
    m_bagOpMgr->Commit();
    
    // 创建新的操作管理器获取物品数量
    NFBagPageOpMgr* getMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 获取堆叠物品数量
    int count1 = 0;
    int getResult1 = getMgr->GetItemNum(TestItemIds::STACKABLE_ARROW, count1);
    ASSERT_EQ(getResult1, 0) << "获取堆叠物品数量失败";
    ASSERT_EQ(count1, 150) << "堆叠物品数量不正确";
    
    // 获取普通物品数量
    int count2 = 0;
    int getResult2 = getMgr->GetItemNum(TestItemIds::NORMAL_ITEM_1, count2);
    ASSERT_EQ(getResult2, 0) << "获取普通物品数量失败";
    ASSERT_EQ(count2, 3) << "普通物品数量不正确";
    
    // 获取不存在物品的数量
    int count3 = 0;
    int getResult3 = getMgr->GetItemNum(TestItemIds::WEAPON_SWORD, count3);
    ASSERT_EQ(getResult3, 0) << "获取不存在物品数量失败";
    ASSERT_EQ(count3, 0) << "不存在物品数量应该为0";
}

/**
 * @brief 测试操作管理器状态
 */
TEST_F(BagPageOpMgrTest, OperationManagerStateTest) {
    // 测试初始状态
    ASSERT_EQ(m_bagOpMgr->GetPackageOpReason(), TEST_REASON_SYSTEM) << "操作原因不正确";
    
    // 执行一些操作
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    m_bagOpMgr->AddToBag(willAdd, 1, nullptr);
    
    // 提交操作
    int commitResult = m_bagOpMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "首次提交失败";
    
    // 尝试再次提交应该失败（已经提交过了）
    int secondCommitResult = m_bagOpMgr->Commit();
    ASSERT_NE(secondCommitResult, 0) << "重复提交应该失败";
}

/**
 * @brief 测试预检查提交
 */
TEST_F(BagPageOpMgrTest, PreCheckCommitTest) {
    // 添加一些正常操作
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    m_bagOpMgr->AddToBag(willAdd, 1, nullptr);
    
    // 预检查提交
    int preCheckResult = m_bagOpMgr->PreCheckCommit();
    ASSERT_EQ(preCheckResult, 0) << "预检查提交失败";
    
    // 正式提交
    int commitResult = m_bagOpMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "正式提交失败";
} 